package ec.linde.modulos.dao;

import java.math.BigDecimal;
import java.util.List;
import java.util.Map;

import javax.ejb.Stateless;
import javax.persistence.Query;
import javax.persistence.TypedQuery;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Expression;
import javax.persistence.criteria.Fetch;
import javax.persistence.criteria.JoinType;
import javax.persistence.criteria.Path;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;

import ec.linde.enumeraciones.Estado;
import ec.linde.persistencia.entidades.ProdConceptos;
import ec.linde.persistencia.entidades.ProdPartidaDetalle;
import ec.linde.persistencia.entidades.proyectos.DetallePlanillaContratista;
import ec.linde.persistencia.entidades.proyectos.PlanillaContratista;
import ec.linde.persistencia.entidades.proyectos.Rdo;

/**
 * TODO: Agregar descripcion
 * 
 * @FechaCreacion: 29/09/2014
 * @author: Alex Carrillo
 * @FechaModificacion: 29/09/2014
 * @author: Alex Carrillo
 * @version: 1.0
 */
@Stateless
public class PlanillaContratistaDao extends AbstractDao<PlanillaContratista> {
	/**
	 * Constructor por defecto que inicializa el AbstractDao con la clase ProdPlanillaContratista
	 */
	public PlanillaContratistaDao() {
		super(PlanillaContratista.class);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.asinfo.as2.dao.AbstractDaoAS2#obtenerListaPorPagina(int, int, java.lang.String, boolean, java.util.Map)
	 */
	public List<PlanillaContratista> obtenerListaPorPagina(int startIndex, int pageSize, String sortField, boolean sortOrder,
			Map<String, String> filters) {
		CriteriaBuilder criteriaBuilder = em.getCriteriaBuilder();
		CriteriaQuery<PlanillaContratista> criteriaQuery = criteriaBuilder.createQuery(PlanillaContratista.class);
		Root<PlanillaContratista> from = criteriaQuery.from(PlanillaContratista.class);
		from.fetch("rdo", JoinType.LEFT).fetch("planOperativo", JoinType.LEFT).fetch("proyecto", JoinType.LEFT);

		final List<Expression<?>> expresiones = obtenerExpresiones(filters, criteriaBuilder, from);
		criteriaQuery.where(expresiones.toArray(new Predicate[expresiones.size()]));

		agregarOrdenamiento(sortField, sortOrder, criteriaBuilder, criteriaQuery, from);

		CriteriaQuery<PlanillaContratista> select = criteriaQuery.select(from);
		TypedQuery<PlanillaContratista> typedQuery = em.createQuery(select);
		agregarPaginacion(startIndex, pageSize, typedQuery);

		return typedQuery.getResultList();
	}

	/**
	 * 
	 * Retorna un lista para ser mostrado en un combo
	 * 
	 * @param sortField
	 * @param sortOrder
	 * @param filters
	 * @return
	 */
	public List<PlanillaContratista> obtenerListaCombo(String sortField, boolean sortOrder, Map<String, String> filters) {

		CriteriaBuilder criteriaBuilder = em.getCriteriaBuilder();
		CriteriaQuery<PlanillaContratista> criteriaQuery = criteriaBuilder.createQuery(PlanillaContratista.class);
		Root<PlanillaContratista> from = criteriaQuery.from(PlanillaContratista.class);
		from.fetch("rdo", JoinType.LEFT).fetch("planOperativo", JoinType.LEFT);

		agregarOrdenamiento(sortField, sortOrder, criteriaBuilder, criteriaQuery, from);

		List<Expression<?>> empresiones = obtenerExpresiones(filters, criteriaBuilder, from);
		criteriaQuery.where(empresiones.toArray(new Predicate[empresiones.size()]));

		CriteriaQuery<PlanillaContratista> select = criteriaQuery.select(from);
		TypedQuery<PlanillaContratista> typedQuery = em.createQuery(select);

		return typedQuery.getResultList();
	}

	/**
	 * Carga ProdPlanillaContratista
	 * 
	 * @param idPlanillaContratista
	 * @return ProdPlanillaContratista
	 */
	public PlanillaContratista cargarDetalle(int idPlanillaContratista) {

		CriteriaBuilder criteriaBuilder = em.getCriteriaBuilder();

		CriteriaQuery<PlanillaContratista> cqCabecera = criteriaBuilder.createQuery(PlanillaContratista.class);
		Root<PlanillaContratista> fromCabecera = cqCabecera.from(PlanillaContratista.class);
		Fetch<Object, Object> rdo = fromCabecera.fetch("rdo", JoinType.LEFT);
		Fetch<Object, Object> planOperativo = rdo.fetch("planOperativo", JoinType.LEFT);
		Fetch<Object, Object> proyecto = planOperativo.fetch("proyecto", JoinType.LEFT);

		proyecto.fetch("usuario", JoinType.LEFT);
		proyecto.fetch("persona", JoinType.LEFT);
		proyecto.fetch("cliente", JoinType.LEFT);
		proyecto.fetch("sucursal", JoinType.LEFT);
		proyecto.fetch("contactoCliente", JoinType.LEFT);
		proyecto.fetch("contratista", JoinType.LEFT);
		proyecto.fetch("contactoContratista", JoinType.LEFT);

		Path<Integer> pathId = fromCabecera.get("idPlanillaContratista");
		cqCabecera.where(criteriaBuilder.equal(pathId, idPlanillaContratista));
		CriteriaQuery<PlanillaContratista> selectPlanillaContratista = cqCabecera.select(fromCabecera);
		PlanillaContratista planillaContratista = em.createQuery(selectPlanillaContratista).getSingleResult();

		CriteriaQuery<DetallePlanillaContratista> cqDetallePlanillaContratista = criteriaBuilder.createQuery(DetallePlanillaContratista.class);
		Root<DetallePlanillaContratista> fromDetallePlanillaContratista = cqDetallePlanillaContratista.from(DetallePlanillaContratista.class);
		fromDetallePlanillaContratista.fetch("partida", JoinType.LEFT);
		fromDetallePlanillaContratista.fetch("concepto", JoinType.LEFT);
		cqDetallePlanillaContratista.where(criteriaBuilder.equal(fromDetallePlanillaContratista.join("planillaContratista"), planillaContratista));
		CriteriaQuery<DetallePlanillaContratista> selectDetallePlanillaContratista = cqDetallePlanillaContratista
				.select(fromDetallePlanillaContratista);

		List<DetallePlanillaContratista> listaDetallePlanillaContratista = em.createQuery(selectDetallePlanillaContratista).getResultList();
		planillaContratista.setListaDetallePlanillaContratista(listaDetallePlanillaContratista);

		for (DetallePlanillaContratista dpc : listaDetallePlanillaContratista) {
			em.detach(dpc);
			dpc.setPlanillaContratista(planillaContratista);
		}

		return planillaContratista;
	}

	public void cambiarEstado(int idPlanillaContratista, Estado estado) {
		Query query = em.createQuery("UPDATE PlanillaContratista pl SET pl.estado = :estado WHERE pl.idPlanillaContratista = :idPlanillaContratista");
		query.setParameter("estado", estado);
		query.setParameter("idPlanillaContratista", idPlanillaContratista);
		query.executeUpdate();
	}

	public BigDecimal cantidadPlanillaAnterior(Rdo rdo, ProdPartidaDetalle partida, ProdConceptos concepto) {

		StringBuilder sql = new StringBuilder();
		sql.append(" SELECT 	SUM(dpl.cantidadPlantillaActual) ");
		sql.append(" FROM		DetallePlanillaContratista dpl   ");
		sql.append(" INNER JOIN dpl.planillaContratista    pl    ");
		sql.append(" WHERE  pl.rdo = :rdo ");
		sql.append(" AND    dpl.partida = :partida ");
		sql.append(" AND    dpl.concepto = :concepto ");

		Query query = em.createQuery(sql.toString());
		query.setParameter("rdo", rdo);
		query.setParameter("partida", partida);
		query.setParameter("concepto", concepto);

		return (BigDecimal) query.getSingleResult();

	}
	
	public BigDecimal costoPlanillaAnterior(Rdo rdo, ProdPartidaDetalle partida, ProdConceptos concepto) {

		StringBuilder sql = new StringBuilder();
		sql.append(" SELECT 	SUM(dpl.costoPlanillaActual) ");
		sql.append(" FROM		DetallePlanillaContratista dpl   ");
		sql.append(" INNER JOIN dpl.planillaContratista    pl    ");
		sql.append(" WHERE  pl.rdo = :rdo ");
		sql.append(" AND    dpl.partida = :partida ");
		sql.append(" AND    dpl.concepto = :concepto ");

		Query query = em.createQuery(sql.toString());
		query.setParameter("rdo", rdo);
		query.setParameter("partida", partida);
		query.setParameter("concepto", concepto);

		return (BigDecimal) query.getSingleResult();

	}

}
